Skip to content

fix: Fix legacy authentication for all PLCs with legacy firmware. - #849

Merged
gijzelaerr merged 1 commit into
gijzelaerr:masterfrom
bvanelli:fix/legacy-authentication
Sep 3, 2026
Merged

fix: Fix legacy authentication for all PLCs with legacy firmware.#849
gijzelaerr merged 1 commit into
gijzelaerr:masterfrom
bvanelli:fix/legacy-authentication

Conversation

@bvanelli

@bvanelli bvanelli commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Changes

Important: Marked as draft because the capture bytes requires #848 to be merged, otherwise tests will fail.

Legacy authentication was never really supported, and that caused authentication to fail on old hardware. The previous condition to authenticate with legacy was the cryptography package not being available:

            # Try new-style first, fall back to legacy SHA-1 XOR
            try:
                response_data = build_new_response(password, challenge, self._oms_secret, "")
                self._send_legitimation_new(response_data)
            except NotImplementedError:
                # cryptography package not available, use legacy
                response_data = build_legacy_response(password, challenge)
                self._send_legitimation_legacy(response_data)

The authentication mode is decided by reading the PLC model and firmware version, and using decide_legitimation_mode to decide which auth to use. The LegitimationType also clearly encodes the 1/2 value into an enum.

This uses a capture from the C# driver to implement with a contract test the exact authentication that the legacy PLC expects. The capture was taken with an S7-1512 Series using 2.9.8 firmware.

Testing

Doing a browse and a variable read against a real PLC now works. The legitimation lowers the protection level correct and both the browse and read are successful:

INFO snap7.connection: Connected to 192.168.101.34:102, PDU size: 1024
INFO s7commplus.connection: TLS activated (tunneled inside COTP frames)
INFO s7commplus.connection: ServerSessionVersion captured (87 bytes)
INFO s7commplus.connection: Public key fingerprint captured: 00:181B7B0847D11694
INFO s7commplus.connection: Session challenge captured (20 bytes): 4a828122931ecc402189a828141a20631cd6be7c
INFO s7commplus.connection: Session setup completed successfully
INFO s7commplus.connection: V2 IntegrityId tracking enabled
INFO s7commplus.connection: PLC reports protection level: 4
INFO s7commplus.connection: S7CommPlus connected to 192.168.101.34:102, version=V2, session=1879051449, tls=True
INFO s7commplus.client: Performing PLC legitimation (password authentication)
INFO s7commplus.connection: Using legacy legitimation
INFO s7commplus.connection: Received legitimation challenge (20 bytes)
INFO s7commplus.connection: PLC legitimation completed, protection level 4 -> 2
INFO __main__: Connected to 192.168.101.34: protocol=V2 session=0x70000CB9 session_setup_ok=True tls_active=True
Browse found 23728 variables
Example read:
  LGF_SinusCI_DB.amplitude (REAL) @ 8A0E0007.E
LGF_SinusCI_DB.amplitude (REAL) = 3f800000

The same code, when running it from master, uses the _send_legitimation_new which gets rejected by the PLC:

INFO snap7.connection: Connected to 192.168.101.34:102, PDU size: 1024
INFO s7commplus.connection: TLS activated (tunneled inside COTP frames)
INFO s7commplus.connection: ServerSessionVersion captured (87 bytes)
INFO s7commplus.connection: Public key fingerprint captured: 00:181B7B0847D11694
INFO s7commplus.connection: Session challenge captured (20 bytes): f9a3c61dd5730e484ec329fb6141ea708ca86f3c
INFO s7commplus.connection: Session setup completed successfully
INFO s7commplus.connection: V2 IntegrityId tracking enabled
INFO s7commplus.connection: PLC reports protection level: 4
INFO s7commplus.connection: S7CommPlus connected to 192.168.101.34:102, version=V2, session=1879051449, tls=True
INFO s7commplus.client: Performing PLC legitimation (password authentication)
INFO s7commplus.connection: Received legitimation challenge (20 bytes)
Traceback (most recent call last):
  File "/Users/brunno.vanelli/Documents/git/python-snap7/example/s7commplus1_browse_sync.py", line 29, in <module>
    client.connect(host, use_tls=True, password="[redacted]")
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/brunno.vanelli/Documents/git/python-snap7/s7commplus/client.py", line 114, in connect
    self._open_connection()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/Users/brunno.vanelli/Documents/git/python-snap7/s7commplus/client.py", line 131, in _open_connection
    self._connection.authenticate(p["password"])
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/Users/brunno.vanelli/Documents/git/python-snap7/s7commplus/connection.py", line 530, in authenticate
    self._send_legitimation_new(response_data)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/Users/brunno.vanelli/Documents/git/python-snap7/s7commplus/connection.py", line 579, in _send_legitimation_new
    _check_set_variable_response(resp_payload)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "/Users/brunno.vanelli/Documents/git/python-snap7/s7commplus/connection.py", line 207, in _check_set_variable_response
    raise S7ConnectionError(f"Legitimation rejected by PLC: return_value=0x{return_value:X}")
snap7.error.S7ConnectionError: Legitimation rejected by PLC: return_value=0xC592CC000222FEA1

@bvanelli
bvanelli force-pushed the fix/legacy-authentication branch from ef8f239 to e76f002 Compare September 2, 2026 15:27
@bvanelli
bvanelli marked this pull request as ready for review September 2, 2026 15:54
@bvanelli

bvanelli commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

@gijzelaerr this is now for review. Let me know your thoughts on it.

I used it again to test #820 since our PLC with the safe dummy project only accepts this type of authentication. This will make all other branches easier to test.

@gijzelaerr gijzelaerr left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the firmware-mode selection, PAOM parsing, access-level verification, legitimation payload encoding, and key rotation. Focused authentication tests pass locally, and the full CI matrix is green. No blocking findings.

@gijzelaerr
gijzelaerr merged commit 43e1645 into gijzelaerr:master Sep 3, 2026
41 checks passed
@bvanelli
bvanelli deleted the fix/legacy-authentication branch September 3, 2026 07:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants